home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
program
/
ddj0897.zip
/
OBJECTC.ASC
< prev
next >
Wrap
Text File
|
1997-06-20
|
8KB
|
277 lines
_Dynamic Design Patterns in Objective-C_
by William Grosso
Listing One
// From the header file -- define a pointer to member function for a method
bool appBecameActiveCanBeCalled;
id (* appBecameActive) (id, SEL, id);
// From the .m (code) file (and heavily annotated)
- (void) setDelegate: newDelegate
{
SEL tokenizedMethodName; // the @selector compiler directive tokenizes
// the method name.
// First, we check to see if we have a delegate and, if so, whether the new
// delegate is from the same class; if both these are true, just return.
if ((nil!=_internalDelegate) && ([newDelegate cisMemberOf:
[_internalDelegate class]))
{
_internalDelegate = [newDelegate retain]; //delegate won't be freed
return;
}
// We need to explicitly check which methods our new delegate has implemented.
_internalDelegate = [newDelegate retain]; //ensure delegate won't be freed
tokenizedMethodName=@selector(appBecameActive:);
if (YES==[ newDelegate respondsTo: tokenizedMethodName])
{
// syntax is [object memberFunction: argumentOne tag: argument2 ...]; We now
// know that the new delegate object implements appBecameActive. We will get
// function pointer (for speed, might be calling this function often and
// and therefore want to avoid rebinding the selector). Usually, we wouldn't
// get the function pointer.
AppBecameActive=(id (*) (id, SEL, id)
[_internalDelegate methodFor: tokenizedMethodName];
appBecameActiveCanBeCalled=YES;
}
else
{
appBecameActiveCanBeCalled =NO;
}
// ....
}
Listing Two
// code in main application
- loadObscureClassFromDisk
{
// Our goal is to find a requried class object (which we will return)
Class classThatsNeeded;
// Has it been loaded ? Try to find the class object using a wrapper
// function which encapsulates the run-time function objc_lookUpClass();
classThatsNeeded =NXClassFromString("ObscureClassName");
If (nil== classThatsNeeded)
{
// No class object. We need to load it.
// Build a path name, relative to where application was installed by
// concatenating a subdirectory name onto [[NXApp mainBundle] directory]
char * fullPathDirectory;
....
NXBundle * bundleForClass =[[NXBundle alloc] initForDirectory:
fullPathDirectory];
classThatsNeeded=[ bundleForClass classNamed:"ObscureClassName"];
}
return classThatsNeeded;
}
Listing Three
// code in an element
- (bool) accept: aVisitor
{
// Protocols are like interfaces in javathey define a set of methods.
// Objects, when declared (in their header files), inherit from one concrete
// class and multiple protocols. This accept method checks whether the
// visitor conformsTo (inherits from) a certain protocol declared earlier
// or if the visitor is of a particular class.
if (([aVisitor conformsTo: MyProtocol]) !!
([aVisitor isKindOf: acceptableClass]))
{
return [aVisitor visit: self];
}
return NO;
}
// code in a visitor
- visit: anElement
{
// again, do type checking. Check whether element is an instance of a
// specific class; if that fails, whether it inherits from some other class.
// classOne and classTwo are declared previously.
if ([anElement isMemberOf: classOne])
{
// perform some sequence of actions
}
else if ([anElement isKindOf: classTwo])
{
// perform some sequence of actions
}
return NO;
}
Listing Four
template <Class T> CommandObject
{
private:
T& target
void (T::memberFunctionToCall)();
public:
CommandObject(T& theTarget, void (T::theMemberFunctionToCall)());
void Do();
}
// comment: ask Don to finish this.
Listing Five
// headers -- Serializer implements
- (void) writeInt: (id) value;
- (void) writeFloat: (id) value;
- (void) writeDouble: (id) value
- (void) writeChar: (id) value
- (void) writeObject: (id) value
// Serializable implements
- (void) serializeUsing: (Serializer *) serializerToUse;
- (void) initWithDeserializer: (Deserialier *) deserializerWithMyState;
// Serializer implements
- (int) readInt;
- (float) readFloat;
- (double) readDouble;
- (char) readChar;
- (id) readObject;
// from Serializer's Code
- (void) writeObject: (id) value
{
if (YES==[self objectAlreadyWritten: value])
{
// The object thas already been serialized. We just store the
// internal uuid (so we can rebuild the object graph).
[self storeReferenceToObject: value];
}
else
{
// first log that we're storing the object.
[self createReferenceFor: value];
[self writeString: NSStringFromClass([[value class])];
[value serializeUsing: self];
}
}
// from Deserializer's code
- (id) readObject
{
// ....
// Here we need to exhume a previously unknown object.
Class classObjectForValue;
id value;
classObjectForValue = NSClassFromString([self readNextString]);
if (nil!= classObjectForValue)
{
value=[[ classObjectForValue alloc] initFromSerializer: self];
}
else
{
// Bad thing happened here. Raise an exception because our data is corrupt.
// ...
}
return value;
}
Listing Six
// header (.h) file
#import <foundation/foundation.h>
@interface CommandObject: NSObject
{
id target;
id argument;
NSString * nameOfMethod;
SEL selectorForMethod;
}
- (void) dealloc;
- init;
- (void) setArgumentObject: newArgument;
- (void) setTargetObject: newTarget;
// Function overloading would make the next two methods more pleasant.
- (void) setTargetMethodByString: (NSString *) methodName;
- (void) setTargetMethodBySelector: (SEL) methodSelector;
- (bool) do;
- (void) initWithCoder: (NSCoder *) decoder;
- (void) encodeWithCoder: (NSCoder *) encoder;
@end
// code (.m) file
#import "CommandObject.h"
@implementation CommandObject
- (void) dealloc
{
// retain, release, and autorelease are all part of reference counting.
// ref counting is in NEXTSTEP, but not part of the Objective-C spec.
// When an object's ref count goes to zero, it is deallocated.
[target autorelease];
[argument autorelease];
[nameOfMethod autorelease];
[super dealloc];
return;
}
- init
{
// init is like a constructor. The object has already been
// allocated and needs to have its variables initialized.
[super init];
nameOfMethod=argument=target=nil; //always safe cause messages to nil
//don't cause problems.
return self; //note that the return value of init has to be
//specified, unlike the return value from a
//C++ constructor.
}
- (void) setArgumentObject: newArgument
{
if (nil!=argument)
{
[argument autorelease];
}
argument=newArgument;
[argument retain];
return;
}
- (void) setTargetObject: newTarget
{
if (nil!=target)
{
[target autorelease];
}
target=newTarget;
[target retain];
return;
}
- (void) setTargetMethodByString: (NSString *) methodName
{
nameOfMethod = [methodName copy]; //make our own copy
//to guard against changes
selectorForMethod= NSSelectorFromString (nameOfMethod);
return;
}
- (void) setTargetMethodBySelector: (SEL) methodSelector
{
selectorForMethod= methodSelector;
nameOfMethod= [NSStringFromSelector (selectorForMethod) retain];
return;
}
- (bool) do
{
if (YES==[target respondsTo: selectorForMethod])
{
[target perform: selectorForMethod];
return YES;
}
return NO;
}
- (void) initWithCoder: (NSCoder *) decoder
{
// From target, object, and nameOfMethod, we can get selector back (in fact,
// we'll call function to do so). Hence, object graph can be fully restored.
// ....
}
- (void) encodeWithCoder: (NSCoder *) encoder
{
// We write out three objects--target, argument,and nameOfMethod.
// this is just the "serialize" method discussed earlier.
// ...
}
@end